#include <GUI/Widgets/SwitchWidget.hpp>
#include <FL/Fl_PNG_Image.H>
#include <FL/Fl_Image.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Group.H>
#include <Core/GPIO.h>
#include <GUI/Theme.hpp>
#include <cstdio>
#include <algorithm>
#include <cmath>


#ifndef RESOURCE_DIR
#define RESOURCE_DIR "."
#endif

Fl_PNG_Image* SwitchWidget::s_img_on_ = nullptr;
Fl_PNG_Image* SwitchWidget::s_img_off_ = nullptr;

SwitchWidget::SwitchWidget(int x, int y, int w, int h, int pin_index)
    : Fl_Box(x, y, w, h), pin_index_(pin_index)
{
    box(FL_NO_BOX); // 透明背景，交由父容器绘制
    align(FL_ALIGN_INSIDE);
    ensure_images();
}

SwitchWidget::~SwitchWidget()
{
    if (cached_img_)
    {
        delete cached_img_;
        cached_img_ = nullptr;
    }
}

void SwitchWidget::ensure_images()
{
    if (!s_img_on_)
    {
        char path[512];
        std::snprintf(path, sizeof(path), "%s/switch_on.png", RESOURCE_DIR);
        s_img_on_ = new Fl_PNG_Image(path);
        if (s_img_on_->fail())
        {
            std::fprintf(stderr, "[SwitchWidget] 加载失败: %s\n", path);
            delete s_img_on_;
            s_img_on_ = nullptr;
        }
    }
    if (!s_img_off_)
    {
        char path[512];
        std::snprintf(path, sizeof(path), "%s/switch_off.png", RESOURCE_DIR);
        s_img_off_ = new Fl_PNG_Image(path);
        if (s_img_off_->fail())
        {
            std::fprintf(stderr, "[SwitchWidget] 加载失败: %s\n", path);
            delete s_img_off_;
            s_img_off_ = nullptr;
        }
    }
}

void SwitchWidget::rebuild_cache_if_needed(int area_w, int area_h)
{
    ensure_images();
    Fl_PNG_Image* src = is_on_ ? s_img_on_ : s_img_off_;
    if (!src) return;

    if (cached_img_ && cached_area_w_ == area_w && cached_area_h_ == area_h && cached_on_ == is_on_)
        return;

    if (cached_img_)
    {
        delete cached_img_;
        cached_img_ = nullptr;
    }

    double sx = area_w / (double)src->w();
    double sy = area_h / (double)src->h();
    double s = std::min(sx, sy);
    if (s <= 0.0) s = 1.0;
    int dw = std::max(1, (int)std::floor(src->w() * s));
    int dh = std::max(1, (int)std::floor(src->h() * s));
    cached_img_ = src->copy(dw, dh);
    cached_area_w_ = area_w;
    cached_area_h_ = area_h;
    cached_on_ = is_on_;
}

void SwitchWidget::set_state(bool on)
{
    if (is_on_ == on) return;
    is_on_ = on;
    if (cached_img_)
    {
        delete cached_img_;
        cached_img_ = nullptr;
    }
    cached_area_w_ = cached_area_h_ = 0;
    cached_on_ = is_on_;
    redraw();
}

void SwitchWidget::sync_from_port()
{
    int mask = (1 << pin_index_);
    bool on = (GPIO.IDR & mask) != 0;
    set_state(on);
}

void SwitchWidget::write_port()
{
    int mask = (1 << pin_index_);
    if (is_on_) GPIO.IDR |= mask;
    else GPIO.IDR &= ~mask;
}

void SwitchWidget::draw()
{
    int tx = x();
    int ty = y();
    int W = w();
    int H = h();

    fl_push_clip(tx, ty, W, H);
    // 清理背景，避免重影
    Fl_Color bg = parent() ? parent()->color() : GUI::current_theme().card_bg;
    fl_color(bg);
    fl_rectf(tx, ty, W, H);

    const auto& th = GUI::current_theme();
    const int text_h = 18; // 底部文字高度

    // 图片区域为去掉底部文字后的区域
    int area_w = W;
    int area_h = std::max(1, H - text_h);

    rebuild_cache_if_needed(area_w, area_h);
    if (cached_img_)
    {
        int dx = tx + (area_w - cached_img_->w()) / 2;
        int dy = ty + (area_h - cached_img_->h()) / 2;
        cached_img_->draw(dx, dy);
    }

    // 画底部 GPIO 文本
    char label_buf[32];
    std::snprintf(label_buf, sizeof(label_buf), "GPIO%d", pin_index_);
    fl_font(FL_HELVETICA_BOLD, 13);
    fl_color(th.text_secondary);
    fl_draw(label_buf, tx, ty + H - text_h, W, text_h, FL_ALIGN_CENTER | FL_ALIGN_INSIDE);

    fl_pop_clip();
}

int SwitchWidget::handle(int event)
{
    switch (event)
    {
    case FL_PUSH:
    case FL_DRAG:
    case FL_RELEASE:
        {
            int mx = Fl::event_x();
            int my = Fl::event_y();
            if (mx >= x() && mx < x() + w() && my >= y() && my < y() + h())
            {
                // 上半区 -> ON，下半区 -> OFF（不含底部文字区域）
                int click_y = my - y();
                int effective_h = std::max(1, h() - 18); // 与绘制一致
                bool on = click_y < (effective_h / 2);
                if (is_on_ != on || event == FL_RELEASE)
                {
                    is_on_ = on;
                    write_port();
                    cached_on_ = !on; // 强制重建
                    redraw();
                }
                return 1;
            }
            break;
        }
    default: break;
    }
    return Fl_Box::handle(event);
}
